package com.kollway.update;

import android.app.IntentService;
import android.app.PendingIntent;
import android.content.Intent;
import android.content.res.Resources;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.widget.Toast;

import com.kollway.update.util.NotificationUtil;

import org.apache.commons.io.IOUtils;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;
import java.util.Map;

/**
 * Created by lyaotian on 1/22/17.
 */

public class DownloadService extends IntentService {
    public static final String KEY_DATA = "KEY_DATA";
    private static final Handler uiHandler = new Handler(Looper.getMainLooper());

    private NotificationUtil notify;
    private State state = State.DOWNLOADING;
    private int downloadPercent = 0;
    private Data data = new Data();
    private final Runnable showProgress = new Runnable() {
        @Override
        public void run() {
            boolean isOngoing = state == State.READY || state == State.DOWNLOADING;
            Resources resources = getResources();

            DownloadService service = DownloadService.this;
            switch (state) {
                case READY:
                case DOWNLOADING: {
                    int icon = R.drawable.ic_downloading;
                    String message = resources.getString(R.string.downloading_progress, downloadPercent + "");
                    notify.show(
                            R.id.notification,
                            notify.builder(icon, data.appName, message, false, isOngoing, null, data.pendingIntent));
                    break;
                }
                case FINISH: {
                    int icon = R.drawable.ic_finish;
                    String message = resources.getString(R.string.click_install);
                    Intent installIntent = AndroidUtil.getInstallIntent(service, getApkFile());
                    data.pendingIntent = PendingIntent.getActivity(service, 0, installIntent, PendingIntent.FLAG_CANCEL_CURRENT);
                    notify.show(
                            R.id.notification,
                            notify.builder(icon, data.appName, message, false, isOngoing, null, data.pendingIntent));

                    if (data.autoInstall) {
                        service.startActivity(installIntent);
                    }
                    break;
                }
                case ERROR: {
                    int icon = R.drawable.ic_warning;
                    String message = resources.getString(R.string.download_failed);
                    Intent myIntent = new Intent(service, DownloadService.class);
                    myIntent.putExtra(KEY_DATA, service.data);
                    data.pendingIntent = PendingIntent.getService(service, 0, myIntent, PendingIntent.FLAG_CANCEL_CURRENT);
                    notify.show(
                            R.id.notification,
                            notify.builder(icon, data.appName, message, false, isOngoing, null, data.pendingIntent));
                    break;
                }
            }

            if (isOngoing) {
                uiHandler.postDelayed(this, 1000);
            }else {
                uiHandler.removeCallbacks(this);
            }
        }
    };

    public DownloadService() {
        super(DownloadService.class.getName());
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        if (state == State.READY) {
            Data tmp = intent.getParcelableExtra(KEY_DATA);
            if (tmp != null){
                this.data = tmp;

                //如果已经下载好了
                File apkFile = getApkFile();
                if (apkFile.exists()) {
                    downloadPercent = 100;
                    state = State.FINISH;
                }else{
                    String urlString = data.url;
                    if (!TextUtils.isEmpty(urlString)) {
                        download(urlString);
                    }
                }
            }
            stopSelf();
        }
    }

    private void download(String urlString) {
        BufferedInputStream input = null;
        BufferedOutputStream output = null;
        HttpURLConnection connection = null;
        try {
            state = State.DOWNLOADING;
            URL url = new URL(urlString);
            connection = (HttpURLConnection) url.openConnection();

            int fileSize = 0;
            int downloadSize = 0;
            Map<String, List<String>> headers = connection.getHeaderFields();
            List<String> headerValue = headers.get("Content-Length");
            if (headerValue != null && !headers.isEmpty()) {
                try {
                    fileSize = Integer.parseInt(headerValue.get(0));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            int bufSize = 2048;
            input = new BufferedInputStream(connection.getInputStream(), bufSize);
            File outFile = getTmpFile();
            if (outFile.exists()) {
                outFile.delete();
            }
            output = new BufferedOutputStream(new FileOutputStream(outFile));

            byte[] contents = new byte[bufSize];
            int len;
            while ((len = input.read(contents)) > 0) {
                output.write(contents, 0, len);
                downloadSize += len;
                double percent = ((double)downloadSize)/fileSize*100;
                downloadPercent = Math.min((int) percent, 99);
            }

            if (outFile.renameTo(getApkFile())) {
                downloadPercent = 100;
                state = State.FINISH;
            }
            stopSelf();
        } catch (Exception e) {
            state = State.ERROR;
            e.printStackTrace();
        } finally {
            if (connection != null) {
                connection.disconnect();
            }
            IOUtils.closeQuietly(input);
            IOUtils.closeQuietly(output);
        }
    }

    @Nullable
    private File getMyCacheDir() {
        if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            Toast.makeText(this, getResources().getString(R.string.no_sdcard), Toast.LENGTH_SHORT).show();
            return null;
        }
        File cacheDir = getExternalCacheDir();
        if (cacheDir == null) {
            cacheDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
        }
        return cacheDir;
    }

    private File getTmpFile() {
        File cacheDir = getMyCacheDir();
        if (cacheDir != null) {
            if (!cacheDir.exists()) {
                cacheDir.mkdirs();
            }
        }
        return new File(cacheDir, "update.tmp");
    }

    private File getApkFile() {
        File cacheDir = getMyCacheDir();
        if (cacheDir != null) {
            if (!cacheDir.exists()) {
                cacheDir.mkdirs();
            }
        }
        return new File(cacheDir, "update_" + data.appVersionCode + ".apk");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        state = State.READY;
        notify = new NotificationUtil(this);
        uiHandler.post(showProgress);
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    public enum State {
        READY,
        DOWNLOADING,
        FINISH,
        ERROR
    }

    public static class Data implements Parcelable {

        public String appName = "";
        public int appVersionCode;
        public boolean autoInstall;
        public String url;
        public PendingIntent pendingIntent;

        public Data() {

        }

        protected Data(Parcel in) {
            appName = in.readString();
            appVersionCode = in.readInt();
            autoInstall = in.readInt() == 1;
            url = in.readString();
            pendingIntent = in.readParcelable(PendingIntent.class.getClassLoader());
        }

        public static final Creator<Data> CREATOR = new Creator<Data>() {
            @Override
            public Data createFromParcel(Parcel in) {
                return new Data(in);
            }

            @Override
            public Data[] newArray(int size) {
                return new Data[size];
            }
        };

        @Override
        public int describeContents() {
            return 0;
        }

        @Override
        public void writeToParcel(Parcel dest, int flags) {
            dest.writeString(appName);
            dest.writeInt(appVersionCode);
            dest.writeInt(autoInstall ? 1 : 0);
            dest.writeString(url);
            dest.writeParcelable(pendingIntent, flags);
        }
    }
}
